package com.carsa.blackberry;

import java.io.IOException;
import java.util.Enumeration;

import com.carsa.blackberry.domain.dto.DriversQueueDTO;
import com.carsa.blackberry.domain.dto.QueueDTO;
import com.carsa.blackberry.domain.dto.QueueMessageDTO;
import com.carsa.blackberry.domain.services.impl.GenericServiceImpl;
import com.carsa.blackberry.domain.services.webServices.WebServiceManager;
import com.carsa.blackberry.ui.screen.LoadingScreen;
import com.carsa.blackberry.util.DeviceUtil;
import com.carsa.blackberry.util.Logger;
import com.carsa.blackberry.util.Util;
import com.carsa.blackberry.util.XMLHandler;
import com.carsa.blackberry.util.persistence.FileHandler;
import com.carsa.blackberry.util.persistence.FileHandlerImpl;

/**
 * @author Nahuel Barrios.
 * @since 10/08/2010.
 * @version 1.0
 * @Information Esta clase es la encargada de cada un cierto periodo de tiempo, mediante un segundo thread de ejecucion,
 *              ver si hay conexion disponible para persistir todo lo que el usuario haya hecho desde la ultima
 *              persistencia hecha.
 */
public class ThreadPersistence implements Runnable {

    private GenericServiceImpl _genericService = new GenericServiceImpl();

    public void run() {

	LoadingScreen loadingScreen = CarsaApp.getUIThread().getLoadingScreen();

	if (!DeviceUtil.hasConnection()) {
//	    if (false) {// TODO : Functionality : ver el tema de preguntar si el dispositivo tiene conexion
	    Logger.logInfo("No hay conexion disponible, por lo tanto se cerrara la aplicacion.");
	    loadingScreen.putCloseAppButton();
	    return;
	}

	loadingScreen.setProgressBarValue(25);

	this.loadLegajosOnMemory();
	CarsaApp.getMemory().put(MainKeys.PARAMETER_LEGAJOS, Dummy.getLegajos());// TODO : Dummy : Legajos
	
	loadingScreen.putContinueButton();

	while (true) {
	    try {
		XMLHandler xmlQueue = new XMLHandler();

		// Si hay una conexion disponible, y existe informacion lista
		// para procesar, entonces la persisto.
		// TODO : Functionality : Descomentar y esto, pero OJO porque no anda bien creo. Hay que probarlo.
		if (DeviceUtil.hasConnection() && isAnyDataToPersist(xmlQueue))
		    persistDataFromQueue(xmlQueue);

		// Hago que el thread espere un cierto periodo de tiempo para volver a intentar persistir el archivo.
		Thread.sleep(MainKeys.TIME_PERSIST_INTERVAL_THREAD);

	    }
	    catch (InterruptedException e) {
		Logger.logError(
		                Logger.getLocationMessageFor(this, "run()")
		                        + " cuando se estaba esperando el intervalo de tiempo indicado para seguir con la ejecucion del thread.",
		                e);
	    }
	    catch (Exception e) {
		Logger.logError(Logger.getLocationMessageFor(this, "run()"), e);
	    }

	}// End while.
    }

    /**
     * Recupera la informacion del archivo de persistencia y encola el mensaje para su posterior tratamiento.
     * 
     * @param aMessage
     *            El {@link QueueMessageDTO} que se quiere persistir.
     */
    public void pushMessageIntoQueue(QueueMessageDTO aMessage) {
	XMLHandler xmlQueue = null;

	String fileData = this.getDataFromPersistenceFile();

	QueueDTO queue = null;
	if (fileData != null && !fileData.equals("")) {
	    xmlQueue= new XMLHandler(fileData);// TODO : Test: este paso seria innecesario?
	    queue = new QueueDTO(xmlQueue.toXMLString());
	} else {
	    queue = new QueueDTO();
	}

	queue.addMessage(aMessage);

	this.exportQueueToPersistenceFile(queue);
    }

    /**
     * Persiste la informacion de la cola.
     * 
     * @param xmlQueue
     *            Un {@link XMLHandler} con toda la informacion del archivo de persistencia.
     * @return <code>true</code> cuando se pudo persistir toda la informacion de la cola. O <code>false</code> cuando
     *         hubo al menos un mensaje que no pudo ser persistido.
     */
    private boolean persistDataFromQueue(XMLHandler xmlQueue) {
	QueueDTO currentQueue = new QueueDTO(xmlQueue.toString());

	// Creo la nueva cola que voy a persistir con aquellos mensajes que no
	// hayan podido ser persistidos.
	QueueDTO aNewQueue = new QueueDTO();
	aNewQueue.setXmlVersionTag(currentQueue.getXmlVersionTag());

	// Itero los mensajes y los persisto uno a uno. Aquellos que no puedan
	// ser persistidos, los guardo en una nueva cola que voy a grabar en el
	// archivo de persistencia.
	boolean dataWasPersisted = false;
	Enumeration messages = currentQueue.getMessages().elements();
	while (messages.hasMoreElements()) {
	    QueueMessageDTO aMessage = (QueueMessageDTO) messages.nextElement();

	    // Intento persistir el mensaje.
	    dataWasPersisted = new WebServiceManager().persist(aMessage);

	    // Si el mensaje NO fue persistido, entonces lo vuelvo a encolar.
	    if (!dataWasPersisted)
		aNewQueue.addMessage(aMessage);
	}
	Logger.logInfo("El resultado de persistir la informacion fue: " + String.valueOf(dataWasPersisted));

	// Finalmente reemplazo la cola anterior, por la nueva cola que puede o
	// no tener mensajes.
	this.exportQueueToPersistenceFile(aNewQueue);

	return dataWasPersisted;
    }

    /**
     * Exporta la cola aNewQueue al archivo de persistencia de mensajes.
     * 
     * @param aNewQueue
     *            La nueva cola de mensajes.
     */
    private void exportQueueToPersistenceFile(QueueDTO aNewQueue) {

	FileHandler fHandler = new FileHandlerImpl();
	fHandler.entablishConnection(MainKeys.FILE_PATH_PERSISTENCE_QUEUE);

	if (!fHandler.overwriteWith(aNewQueue.toXmlString()))
	    Logger.logError("No se pudo reencolar los mensajes que no fueron persistidos. Estos mensajes se perderan.");
    }

    /**
     * Chequea que haya alguna informacion lista para ser persistida cuando haya una conexion disponible. Setea el
     * parametro xmlQueue con el {@link String} en formato XML que se obtiene del archivo de persistencia.
     * 
     * @param xmlQueue
     *            El {@link XMLHandler} al que se le seteara la informacion del archivo de persistencia.
     * @return <code>true</code> cuando hay informacion lista, <code>false</code> en caso contrario.
     */
    private boolean isAnyDataToPersist(XMLHandler xmlQueue) {
	String fileData = this.getDataFromPersistenceFile();

	if (fileData == null || fileData.equals(""))
	    return false;

	xmlQueue.setXml(fileData);

	return Util.getBooleanConditionFrom(xmlQueue.getElementValue(QueueDTO.XML_ELEMENT_IS_ANY_MESSAGE));
    }

    /**
     * @return Un {@link String} conteniendo toda la informacion del archivo de persistencia de mensajes.
     */
    private String getDataFromPersistenceFile() {
	FileHandler fHandler = new FileHandlerImpl();
	fHandler.entablishConnection(MainKeys.FILE_PATH_PERSISTENCE_QUEUE);

	String fileData = "";
	try {
	    fileData = fHandler.getFileData();
	}
	catch (IOException e) {
	    Logger.logError(Logger.getLocationMessageFor(this, "getDataFromPersistenceFile()")
		    + " intentando recuperar el contenido del archivo de la cola de persistencia.", e);
	}
	Logger.logDebug("La informacion recuperada del archivos es:\n" + fileData);
	return fileData;
    }

    /**
     * Recupera los legajos y los carga en la memoria de la aplicacion {@link CarsaApp}.getMemory(). En caso de que por
     * algun motivo no se pudieran recuperar los legajos utilizando el Web Service, entonces no setea nada.
     * 
     * @return <code>true</code> si se pudo setear la variable {@link MainKeys}.PARAMETER_LEGAJOS en la memoria de la
     *         app, o <code>false</code> si no se pudo.
     */
    public boolean loadLegajosOnMemory() {
	DriversQueueDTO legajos = _genericService.fetchLegajos();
	if (legajos != null) {
	    CarsaApp.getMemory().put(MainKeys.PARAMETER_LEGAJOS, legajos);
	    return true;
	}
	return false;
    }

}
